from Config.myConstant import *
from Config.myConfig import *
from DataAccess.TradedayDataProcess import TradedayDataProcess
from DataPrepare.tickFactorsProcess import tickFactorsProcess
from DataAccess.KLineDataProcess import KLineDataProcess
from DataPrepare.dailyFactorsProcess import dailyFactorsProcess
from Utility.JobLibUtility import JobLibUtility
from typing import List as type_list
from Strategy.baseStrategy.baseStrategy import baseStrategy
import pandas as pd
import numpy as np
import math
import xgboost as xgb
import warnings
from DataAccess.TickDataProcess import TickDataProcess
from DataPrepare.tickFactors.tickDataPrepared import tickDataPrepared
from DataAccess.IndexComponentDataProcess import IndexComponentDataProcess
from Utility.InfluxdbUtility import InfluxdbUtility
########################################################################
class gradeStrategyCNN(baseStrategy):
    """按照预测值进行交易"""
    #----------------------------------------------------------------------
    def __init__(self):
        self.name='按照CNN的预测值进行交易'
        pass
    #----------------------------------------------------------------------
    def multipleCodes_parallel(self,codes:type_list[str],startDate:str,endDate:str,parameters=[]):
        mydata=JobLibUtility.useJobLibToComputeByCodes(self.multipleCodes,codes,MYGROUPS,startDate,endDate,parameters)
        return mydata
        pass
    #----------------------------------------------------------------------
    #输入code=600000.SH，startdate=yyyyMMdd，endDate=yyyyMMdd
    def multipleCodes(self,codes:type_list[str],startDate:str,endDate:str,parameters=[]):
        mydata=[]
        for i in range(len(codes)):
            code=codes[i]
            data=self.singleCode(code,startDate,endDate,parameters)
            mydata.append(data)
        mydata=pd.concat(mydata)
        return mydata
    
    #----------------------------------------------------------------------
    def singleCode(self,code:str,startDate:str,endDate:str,parameters=[]):
        startDate=str(startDate)
        endDate=str(endDate)
        days=list(TradedayDataProcess().getTradedays(startDate,endDate))
        myWeight=IndexComponentDataProcess.getStockPropertyInIndex(code,HS300,startDate,endDate)
        tick=TickDataProcess()
        tickFactor=tickDataPrepared()
        featureColumns=['predictMaxNext5mAllNOBN','predictMinNext5mAllNOBN']
        newFeatureColumns=['predictMaxNext5m','predictMinNext5m']
        trade=[]
        for day in days:
            tickData=tick.getTickShotDataFromInfluxdbServer(code,day)
            if tickData.shape[0]==0:
                continue
            preClose=tickData['dailyPreClose'].iloc[0]
            #data=tickDataPrepared.getTickFactorDataFromInfluxdb(code,day,columns=featureColumns)
            data=InfluxdbUtility.getDataFromInfluxdb(code,day,'MaoTickPredict20190708',columns=featureColumns)
            if data.shape[0]==0:
                continue
            data[newFeatureColumns]=data[featureColumns]
            tickData=pd.merge(tickData,data,how='left',left_index=True,right_index=True)
            weight=myWeight[myWeight.index==str(day)]['weight'].iloc[0]
            if np.isnan(weight)==True:
                continue;
            maxPosition=round(100000000*(weight/100)/preClose,-2)
            maxExposure=round(50000/preClose,-2)
            if maxPosition<100:
                continue
            parameters={'maxPosition':maxPosition,'maxExposure':maxExposure,'longOpen':0.015,'shortOpen':-0.015,'longClose':0.01,'shortClose':-0.01,'transactionRatio':1}
            for col in featureColumns:
                if (col in list(tickData.columns))==False:
                    continue
                if tickData[col].isna().sum()==tickData.shape[0]:
                    continue
            trade0=self.strategy(tickData,parameters)
            trade.append(trade0)
            pass
        if len(trade)==0:
            trade=pd.DataFrame()
        else:
            trade=pd.concat(trade)
            if trade.shape[0]==0:
                return pd.DataFrame()
            trade['code']=code
            trade['fee']=trade['price']*0.0001
            selectBuy=trade['direction']=='buy'
            selectSell=trade['direction']=='sell'
            trade.loc[selectSell,'fee']=(trade['fee']+trade['price']*0.001)[selectSell]
            trade.loc[selectBuy,'cashChange']=((-trade['price']-trade['fee'])*trade['volume'])[selectBuy]
            trade.loc[selectSell,'cashChange']=((trade['price']-trade['fee'])*trade['volume'])[selectSell]
            trade['amount']=trade['price']*trade['volume']
            logger.info(f'backtest of {code} complete!!')
        return trade
        pass
     #----------------------------------------------------------------------
    def strategy(self,data:pd.DataFrame,parameters):
        
        maxPosition=parameters['maxPosition']
        maxExposure=parameters['maxExposure']
        longOpen=parameters['longOpen']
        longClose=parameters['longClose']
        shortOpen=parameters['shortOpen']
        shortClose=parameters['shortClose']
        transactionRatio=parameters['transactionRatio']
        unusedPosition=maxPosition
        todayPosition=0
        myindex={}
        select=list(data.columns)
        for item in data.columns:
            myindex.update({item:select.index(item)})
        mydata=data.values
        openPrice=0
        maxPrice=0
        minPrice=9999
        stop=False
        maxDownDraw=0
        openDownDraw=0
        holdExposure=0
        openIndex=0
        holdTime=0
        trade=[]
        dict={}
        for i in range(len(mydata)):
           tick=mydata[i] 
           maxPredict=tick[myindex['predictMaxNext5m']]/100.0
           minPredict=tick[myindex['predictMinNext5m']]/100.0
           midPredict=(maxPredict+minPredict)/2
           longkelly=maxPredict+2*minPredict
           shortkelly=minPredict+2*maxPredict
           realData=tick[myindex['realData']]
           S1=tick[myindex['S1']]
           B1=tick[myindex['B1']]
           mid=(S1+B1)/2
           SV1=tick[myindex['SV1']]
           BV1=tick[myindex['BV1']]
           time=tick[myindex['tick']]
           date=tick[myindex['date']]
           increaseToday=tick[myindex['midPrice']]/tick[myindex['dailyPreClose']]-1
           #遇上涨跌停直接不做
           if (abs(increaseToday)>=0.095) & (todayPosition==0):
               break
           #止盈止损
           if todayPosition>0:
               if mid>maxPrice:
                   maxPrice=mid
               maxDownDraw=min(0,(mid-maxPrice)/openPrice)
               openDownDraw=min(0,(mid-openPrice)/openPrice)
               if openIndex>0:
                   holdTime=i-openIndex
               if openDownDraw<=-0.01:
                   stop=True
               else:
                   stop=False
               #if (B1-openPrice)/openPrice>=0.005:
               #    stop=True
               pass
           elif todayPosition<0:
               if mid<minPrice:
                   minPrice=mid
               maxDownDraw=min(0,(minPrice-mid)/openPrice)
               openDownDraw=min(0,(openPrice-mid)/openPrice)
               if openIndex>0:
                   holdTime=i-openIndex
               if openDownDraw<=-0.01:
                   stop=True
               else:
                   stop=False
               #if (openPrice-S1)/openPrice>=0.005:
               #   stop=True
               pass
           if (unusedPosition>0) & (realData==1) & (time>'093100000') & (time<'145000000'):#仍然可以开仓
               if (SV1>=100/transactionRatio) & (increaseToday>-0.09):
                   if (maxPredict>0.005)&(longkelly>0) & (todayPosition==0):
                       transactionVolume=min(round(transactionRatio*SV1,-2),unusedPosition,maxExposure-holdExposure)
                       if transactionVolume>=0:
                           holdExposure=holdExposure+transactionVolume
                           unusedPosition=unusedPosition-transactionVolume
                           todayPosition=todayPosition+transactionVolume
                           transactionPrice=S1
                           transactionTime=time
                           transactionDate=date
                           openIndex=i
                           dict={'date':transactionDate,'tick':transactionTime,'direction':'buy','volume':transactionVolume,'price':transactionPrice,'longshort':'long'}
                           trade.append(dict)
                           if openPrice==0:
                               openPrice=transactionPrice
                               maxPrice=openPrice
                               maxDownDraw=0
                               openDownDraw=0
                           pass
               if (BV1>=100/transactionRatio)& (increaseToday<0.09):
                   if (minPredict<-0.005)&(shortkelly<0) & (todayPosition==0):
                       transactionVolume=min(round(transactionRatio*BV1,-2),unusedPosition,maxExposure-holdExposure)
                       if transactionVolume>=0:
                           holdExposure=holdExposure+transactionVolume
                           unusedPosition=unusedPosition-transactionVolume
                           todayPosition=todayPosition-transactionVolume
                           transactionPrice=B1
                           transactionTime=time
                           transactionDate=date
                           openIndex=i
                           dict={'date':transactionDate,'tick':transactionTime,'direction':'sell','volume':transactionVolume,'price':transactionPrice,'longshort':'short'}
                           trade.append(dict)
                           if openPrice==0:
                               openPrice=transactionPrice
                               minPrice=openPrice
                               maxDownDraw=0
                               openDownDraw=0
                           pass
           if todayPosition!=0:
               if todayPosition>0:#持有多仓
                   #if  ((holdTime>200) &(stop==True))|(time>='145500000') | (increaseToday<-0.095) |((maxPredict<-openDownDraw) & (openDownDraw<-0.005)) :
                   if  ((stop==True))|(time>='145500000') | (increaseToday<-0.095)| ((maxDownDraw<-0.005)&(holdTime>200)) :
                       [averagePrice,sellPosition]=super().sellByTickShotData(tick,myindex,abs(todayPosition),0.05)
                       transactionVolume=sellPosition
                       todayPosition=todayPosition-transactionVolume
                       transactionPrice=averagePrice
                       transactionTime=time
                       transactionDate=date
                       dict={'date':transactionDate,'tick':transactionTime,'direction':'sell','volume':transactionVolume,'price':transactionPrice,'longshort':'long'}
                       trade.append(dict)
                       if todayPosition==0:
                           openPrice=0
                           maxPrice=0
                           minPrice=9999
                           maxDownDraw=0
                           openDownDraw=0
                           holdExposure=0
                           openIndex=0
                           holdTime=0
                           stop=False
                       pass
                   pass
               elif todayPosition<0:#持有空仓
                   #if ((holdTime>200) &(stop==True))|(time>='145500000')| (increaseToday>0.095)|((minPredict>openDownDraw) & (openDownDraw<-0.005)) | ((holdTime>200)& (minPredict>-0.003)) :
                   if ((stop==True))|(time>='145500000')| (increaseToday>0.095)|((maxDownDraw<-0.005)&(holdTime>200)):
                       [averagePrice,buyPosition]=super().buyByTickShotData(tick,myindex,abs(todayPosition),0.05)
                       transactionVolume=buyPosition
                       todayPosition=todayPosition+transactionVolume
                       transactionPrice=averagePrice
                       transactionTime=time
                       transactionDate=date
                       dict={'date':transactionDate,'tick':transactionTime,'direction':'buy','volume':transactionVolume,'price':transactionPrice,'longshort':'short'}
                       trade.append(dict)
                       if todayPosition==0:
                           openPrice=0
                           maxPrice=0
                           minPrice=9999
                           maxDownDraw=0
                           holdExposure=0
                           openIndex=0
                           holdTime=0
                           stop=False
                       pass
                   pass
        trade=pd.DataFrame(data=trade)    
        #print(trade)
        return trade
########################################################################